import { useState } from "react"; const SITES = [ { id: "oracle", emoji: "๐Ÿ”ฎ", name: "The Oracle", tagline: "Receive your prophecy", color: "#c9a84c", desc: "Main revenue hub โ€” AI prophecies, Ko-fi tips, wax seal reveal", kofi: true, }, { id: "tarot", emoji: "๐Ÿƒ", name: "Midnight Tarot", tagline: "Let the cards speak", color: "#9b59b6", desc: "3-card spread with AI interpretation โ†’ links to Oracle", kofi: false, }, { id: "horoscope", emoji: "โญ", name: "Celestial Signs", tagline: "Your stars, decoded", color: "#4ecdc4", desc: "Daily horoscope by zodiac sign โ€” repeat visitors daily", kofi: false, }, { id: "dreams", emoji: "๐Ÿ’ญ", name: "Dream Weaver", tagline: "What your dreams reveal", color: "#e74c3c", desc: "Input your dream โ†’ mystical AI interpretation โ†’ Oracle CTA", kofi: false, }, { id: "numerology", emoji: "๐Ÿ”ข", name: "Numbers & Fate", tagline: "Your number holds your destiny", color: "#2ecc71", desc: "Name + birthdate โ†’ life path number โ€” SEO powerhouse", kofi: false, }, { id: "manifestation", emoji: "โœจ", name: "Manifest Daily", tagline: "Speak your reality into existence", color: "#ff6b9d", desc: "Daily affirmation generator โ€” builds loyal returning users", kofi: false, }, ]; function generateHTML(site, groqKey, oracleUrl) { const prompts = { oracle: `You are a mystical oracle from an ancient realm. The user seeks a prophecy. Give a deeply personal, poetic prophecy of 3-4 sentences. Be mysterious, evocative, and slightly cryptic. Use beautiful language. End with a short warning or gift. Do NOT use bullet points.`, tarot: `You are a tarot master. The user has drawn 3 cards: Past, Present, Future. Generate 3 fitting tarot card names and give a flowing, narrative reading of 3-4 sentences connecting all three. Be mystical and poetic.`, horoscope: `You are an astrologer channeling cosmic wisdom. Give today's horoscope for the provided zodiac sign. 3-4 sentences, personal and specific, covering love, career, and energy. Be evocative and inspiring.`, dreams: `You are a dream interpreter with access to ancient symbolic wisdom. The user describes their dream. Interpret it in 3-4 sentences, revealing hidden meanings, symbols, and what it says about their current life path. Be mystical and insightful.`, numerology: `You are a numerologist. Calculate the life path number from the provided birthdate (sum all digits until single digit, except 11, 22, 33). Reveal its meaning in 3-4 sentences: personality, destiny, and a specific message for this year.`, manifestation: `You are a manifestation guide and life coach. Create a powerful, personalized daily affirmation set of 3 short affirmations based on the user's intention. Make them present-tense, emotionally resonant, and specific. Format: each affirmation on its own line starting with "I ".`, }; const uiBlocks = { oracle: `
`, tarot: `
`, horoscope: `
`, dreams: `
`, numerology: `
`, manifestation: `
`, }; const ctaBlock = site.id !== "oracle" && oracleUrl ? `

โœฆ Seek a deeper personal prophecy

Visit The Oracle โ†’
` : site.id === "oracle" && oracleUrl ? `

If this prophecy moved you...

โ˜• Support the Oracle on Ko-fi
` : ""; const inputScript = site.id === "numerology" ? `const val = document.getElementById('userInput').value; const name = document.getElementById('nameInput')?.value || ''; const userMessage = 'Name: ' + name + ' | Birthdate: ' + val;` : `const val = document.getElementById('userInput').value || document.getElementById('userInput').options?.[document.getElementById('userInput').selectedIndex]?.value || ''; const userMessage = val;`; return ` ${site.name} โ€” ${site.tagline}
${site.emoji}

${site.name}

${site.tagline}

โœฆ โœฆ โœฆ
${uiBlocks[site.id]}

Please fill in the field above.

${site.emoji} The ${site.id === "oracle" ? "oracle" : "spirits are"} reading the signs...

โœฆ YOUR READING โœฆ
${ctaBlock}
`; } export default function OracleGenerator() { const [groqKey, setGroqKey] = useState(""); const [oracleUrl, setOracleUrl] = useState(""); const [selected, setSelected] = useState(null); const [downloaded, setDownloaded] = useState({}); const [step, setStep] = useState("config"); // config | generate | deploy const handleDownload = (site) => { const html = generateHTML(site, groqKey, oracleUrl); const blob = new Blob([html], { type: "text/html" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = `${site.id}.html`; a.click(); URL.revokeObjectURL(url); setDownloaded((d) => ({ ...d, [site.id]: true })); }; const downloadCount = Object.keys(downloaded).length; return (
{/* Header */}
โฌก

Oracle Ecosystem Builder

6 SITES ยท INTERNATIONAL ยท CLOUDFLARE READY

{/* Step tabs */}
{[["config","โ‘  API Keys"], ["generate","โ‘ก Download"], ["deploy","โ‘ข Deploy"]].map(([s, label]) => ( ))}
{/* STEP 1: Config */} {step === "config" && (
setGroqKey(e.target.value)} style={inputStyle} />
Free tier โ€” no credit card needed
setOracleUrl(e.target.value)} style={inputStyle} />
Sites 2โ€“6 will link here automatically
setStep("generate")} disabled={!groqKey}> Continue โ†’ Generate Sites
)} {/* STEP 2: Generate */} {step === "generate" && (
Tap a site to download its index.html โ€” ready to deploy
{SITES.map((site) => (
handleDownload(site)} style={{ background: downloaded[site.id] ? "rgba(46,204,113,0.08)" : "rgba(255,255,255,0.03)", border: `1px solid ${downloaded[site.id] ? "#2ecc71" : "rgba(255,255,255,0.08)"}`, borderRadius: 12, padding: "14px 16px", marginBottom: 10, cursor: "pointer", display: "flex", alignItems: "center", gap: 12, transition: "all 0.2s", userSelect: "none", }}> {site.emoji}
{site.name}
{site.desc}
{downloaded[site.id] ? "โœ“ SAVED" : "โ†“ GET"}
))} {downloadCount > 0 && (
{downloadCount}/6 files downloaded {downloadCount === 6 && " โ€” All sites ready! Go to Deploy โ†’"}
)} {downloadCount > 0 && ( setStep("deploy")} style={{ marginTop: 12 }}> Next โ†’ How to Deploy on Cloudflare )}
)} {/* STEP 3: Deploy Guide */} {step === "deploy" && (
โœฆ THE ONLY METHOD THAT WORKS ON MOBILE โœฆ

Single index.html โ†’ ZIP โ†’ CF Pages Direct Upload.
No build step. No Node. No terminal. No failures.

{[ { n: "1", title: "ZIP your index.html", body: ( <> On Android: Open Files app โ†’ long-press oracle.html โ†’ Compress / Create ZIP
โš ๏ธ The ZIP must contain only index.html (rename from oracle.html to index.html first)
On iPhone: Long-press โ†’ Compress ), }, { n: "2", title: "Go to pages.cloudflare.com", body: <>Log in โ†’ Workers & Pages โ†’ Pages โ†’ Create a project โ†’ "Upload assets" (NOT "Connect Git"), }, { n: "3", title: "Name your project", body: <>Type a name like oracle-main or midnight-tarot โ†’ your URL will be name.pages.dev, }, { n: "4", title: "Upload the ZIP", body: <>Tap "Select from computer" โ†’ choose your ZIP โ†’ wait for upload bar โ†’ tap "Deploy site"
โš ๏ธ Do NOT tap away โ€” wait for the green checkmark, }, { n: "5", title: "Visit your live site", body: <>yourname.pages.dev is live instantly. Free. HTTPS auto. No expiry.
Repeat for all 6 sites with different project names., }, { n: "6", title: "Update a site anytime", body: <>CF Pages โ†’ your project โ†’ Deployments โ†’ "Upload new version" โ†’ upload new ZIP โ†’ Deploy. Done., }, ].map(({ n, title, body }) => (
{n}
{title}
{body}
))} โœฆ FREE TIER LIMITS (Cloudflare Pages)
โœ“ Unlimited sites (up to 100 projects)
โœ“ 500 deployments/month per project
โœ“ Unlimited bandwidth
โœ“ Custom domain (free)
โœ“ Auto HTTPS
โœ“ Forever free โ€” no credit card needed
โœฆ COMMON MISTAKES โ€” AVOID THESE
โŒ ZIP contains a folder instead of the file directly
โŒ File is named oracle.html not index.html
โŒ Choosing "Connect to Git" instead of "Upload assets"
โŒ Closing the tab before deploy finishes
โŒ Using _worker.js or functions/ folder (not needed)
)}
โœฆ ORACLE ECOSYSTEM BUILDER โœฆ
); } // Helper components function Card({ children }) { return (
{children}
); } function Label({ children }) { return (
{children}
); } function InfoBox({ children, color }) { return (
{children}
); } function GoldButton({ children, onClick, disabled }) { return ( ); } const inputStyle = { background: "rgba(255,255,255,0.04)", border: "1px solid rgba(255,255,255,0.1)", borderRadius: 8, color: "#d4c8b0", fontFamily: "Georgia, serif", fontSize: 15, padding: "10px 14px", width: "100%", outline: "none", };